package com.sdyc.ndmp.cls.engine;

import com.google.common.collect.ImmutableMap;
import com.sdyc.ndmp.cls.dtd.KeywordCondition;
import com.sdyc.ndmp.cls.model.MomW;
import com.sdyc.ndmp.cls.model.SonW;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

/**
 *
 * <p>
 *     条件偏移词过滤
 * </p>
 *
 */
public abstract class KeywordVectorFilter implements Filter {

    public static KeywordVectorFilter getFilter(KeywordCondition condition) {
        final Set<KeywordVectorFilter> vectorFilters = new HashSet<KeywordVectorFilter>(2);

        MomW momW = condition.getMomW();
        List<SonW> sons = momW.getSons();

        if(sons == null || sons.isEmpty()) {
            return null;
        }

        for (SonW son : sons) {
            vectorFilters.add(new MatchKeywordVectorFilter(son));
        }

        //TODO 编译 Condition 为 KeywordVectorFilter
        return new AllSetKeywordVectorFilter(vectorFilters);
    }

    @Override
    public boolean accept(DataKeywords post) {
        return accept(post, ImmutableMap.<Match, Set<String>>of());
    }

    /**
     *
     * TODO 使用子类实现该方法
     *
     * 过滤 Keyword 词距
     * @param post Post 内容以及分词
     * @param primeKeywords 主条件词以及匹配模式
     * @return 返回是否匹配成功
     */
    public abstract boolean accept(DataKeywords post, Map<Match, Set<String>> primeKeywords);
}

class AllSetKeywordVectorFilter extends KeywordVectorFilter {

    private final Set<KeywordVectorFilter> vectorFilters;

    public AllSetKeywordVectorFilter(Set<KeywordVectorFilter> vectorFilters) {
        this.vectorFilters = vectorFilters;
    }

    @Override
    public boolean accept(DataKeywords post, Map<Match, Set<String>> primeKeywords) {
        for (KeywordVectorFilter filter : vectorFilters) {
            if(!filter.accept(post, primeKeywords)) {
                return false;
            }
        }
        return true;
    }
}

/**
 *
 * 实现该方法, 实现词距过滤
 *
 */
class MatchKeywordVectorFilter extends KeywordVectorFilter {

    private static Log LOG = LogFactory.getLog(MatchKeywordVectorFilter.class);

    protected final SonW sonW;

    public MatchKeywordVectorFilter(SonW sonW) {
        this.sonW = sonW;
    }

    @Override
    public boolean accept(DataKeywords post, Map<Match, Set<String>> primeKeywords) {
        Iterator<Map.Entry<Match, Set<String>>> iterator = primeKeywords.entrySet().iterator();
        Map.Entry<Match, Set<String>> next = iterator.next();

        Match matchType = next.getKey();
        Set<String> momWordvalue = next.getValue();

        //主关键字下标表
        Map<String,Set<Integer>> momWordIndexTable = getWordIndex(post.getKeywordRangeStart(), momWordvalue, post.getText());

        //TODO 子关键词匹配方式
        //子关键字下标表
        Map<String, Set<Integer>> sonWordsAllIndex = getWordIndex(post.getKeywordRangeStart(), sonW.getWords(),post.getText());
        return isSonW4MPass(momWordIndexTable,matchType,sonWordsAllIndex);
    }

    /**
     * 从内容下标索引表中获得匹配词的索引表
     * @param wordMap
     * @param Words
     * @return
     */
    private Map<String,Set<Integer>> getWordIndex(Map<String,Set<Integer>> wordMap,Set<String> Words,String text){
        Map<String,Set<Integer>> mWordsIndex=new HashMap<String, Set<Integer>>();
        try {
            for(String mWord:Words){
                Set<Integer> tmpIndexs=wordMap.get(mWord);
                if(tmpIndexs!=null) {
                    mWordsIndex.put(mWord, tmpIndexs);
                }else{
                    if(text.toLowerCase().contains(mWord.toLowerCase())){
                        mWordsIndex.put(mWord,indexOf(text,mWord));
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            return new HashMap<String, Set<Integer>>(0);
        }
        return mWordsIndex;
    }

    /**
     * 如果分词失败，备用查找位置方法
     * @param searchStr
     * @param targetStr
     * @return
     */
    private Set<Integer> indexOf(String searchStr,String targetStr){
        Set<Integer> indexSet = new HashSet<Integer>();
        int index =0;
        int tempindex = 0;
        while(true){
            if(searchStr.contains(targetStr)){
                index = searchStr.indexOf(targetStr);
                indexSet.add(index+tempindex);
                tempindex =index+tempindex+1;
                index = index+1;
                searchStr = searchStr.substring(index);
            }else{
                break;
            }
        }
        return indexSet;
    }

    /**
     * 子条件词包含关系匹配
     * @param mWordsAllIndex
     * @param momMatchType
     * @return
     */
    private boolean isSonW4MPass(Map<String,Set<Integer>> mWordsAllIndex, Match momMatchType,Map<String, Set<Integer>> sonWordsAllIndex){
        //LOG.info("条件词匹配>>>>>> "+sonW);
        List<String> passWords=new ArrayList<String>();
        int len = sonW.getLen();
        int vector = sonW.getVector();
        Set<String> sonWords = sonW.getWords();
        int sonWcontains = sonW.getContains();
        Match match = Match.valueOf(sonWcontains);
        for(String mWord:mWordsAllIndex.keySet()) {
                Set<Integer> mWordIndex = mWordsAllIndex.get(mWord);
                boolean flag=false;
                switch (match) {
                    case MATCH_ALL:
                        if (sonWordsAllIndex.size() == sonWords.size()) {
                            switch (vector) {
                                case SonW.VECTOR_PRO:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_PRO, len);
                                    break;
                                case SonW.VECTOR_AFT:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_AFT, len);
                                    break;
                                case SonW.VECTOR_ALL:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_ALL, len);
                                    break;
                            }
                            break;
                        }break;
                    case MATCH_ANY:
                        if (sonWordsAllIndex.size() > 0 && sonWordsAllIndex.size() <= sonWords.size()) {
                            switch (vector) {
                                case SonW.VECTOR_PRO:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_PRO, len);
                                    break;
                                case SonW.VECTOR_AFT:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_AFT, len);
                                    break;
                                case SonW.VECTOR_ALL:
                                    flag=isSubPass(mWord,mWordIndex, sonWordsAllIndex,sonWcontains, SonW.VECTOR_ALL, len);
                                    break;
                            }
                            break;
                        }break;
                    case MATCH_NOT:
                        if (sonWordsAllIndex.size() == 0) {
                            flag=true;break;
                        }break;
                }
            if(flag) {
                passWords.add(mWord);
            }
        }

        switch (momMatchType){
            case MATCH_ALL:
                if(passWords.size()==mWordsAllIndex.size()){return true;}return false;
            case MATCH_ANY:
                if(passWords.size()>0 && passWords.size()==mWordsAllIndex.size()){return true;}return false;
        }

        return false;
    }


    /**
     * 子条件词 向量坐标匹配
     * @param mWord
     * @param mWordIndex
     * @param sonWordIndex
     * @param constens
     * @param vector
     * @param len
     * @return
     */
    private boolean isSubPass(String mWord,Set<Integer> mWordIndex,Map<String,Set<Integer>> sonWordIndex,Integer constens,Integer vector,int len){
        List<String> tmpList=new ArrayList<String>();
        for(int mwi:mWordIndex){
            for(String sonw:sonWordIndex.keySet()){
                boolean isMatch=false;
                for(int swi:sonWordIndex.get(sonw)){
                    int spaceL=0;
                    switch (vector) {
                        case SonW.VECTOR_ALL:
                            if (len < 0) {
                                tmpList.add(sonw);
                                isMatch = true;
                            } else {
                                if (swi < mwi) {
                                    spaceL = mwi - (swi + (sonw.length()));
                                } else {
                                    spaceL = swi - (mwi + (mWord.length()));
                                }
                                if (spaceL <= len) {
                                    tmpList.add(sonw);
                                    isMatch = true;
                                }
                            }
                            break;
                        case SonW.VECTOR_PRO:
                            if (swi < mwi) {
                                if (len < 0) {
                                    tmpList.add(sonw);
                                    isMatch = true;
                                } else {
                                    spaceL = mwi - (swi + (sonw.length()));
                                    if (spaceL <= len) {
                                        tmpList.add(sonw);
                                        isMatch = true;
                                    }
                                }
                            }
                            break;
                        case SonW.VECTOR_AFT:
                            if (swi > mwi) {
                                if (len < 0) {
                                    tmpList.add(sonw);
                                    isMatch = true;
                                } else {
                                    spaceL = swi - (mwi + (mWord.length()));
                                    if (spaceL <= len) {
                                        tmpList.add(sonw);
                                        isMatch = true;
                                    }
                                }
                            }
                    }
                    if(isMatch){
                        break;
                    }
                }
            }
        }

        switch (Match.valueOf(constens)){
            case MATCH_ALL:
                if(tmpList.size()==(sonWordIndex.size()*mWordIndex.size())){
                    return true;
                }return false;
            case MATCH_ANY:
                if(tmpList.size()>0 && tmpList.size()<=(sonWordIndex.size()*mWordIndex.size())){
                    return true;
                }return false;
            case MATCH_NOT:
                if(tmpList.size()==0){
                    return true;
                }return false;
        }

        return false;
    }
}